package com.zlp.exception.handler;


import com.zlp.exception.BaseException;
import com.zlp.exception.BusinessException;
import com.zlp.exception.entity.Response;
import com.zlp.exception.log.Log;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.validation.BindException;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import javax.validation.ValidationException;
import java.util.List;

/**
 * @author: ZouLiPing
 * @date: 2018/10/10 17:58
 * @description: 统一异常处理器
 */
@ControllerAdvice
public class ExceptionHandler {

    Logger logger = LoggerFactory.getLogger(getClass());

    @org.springframework.web.bind.annotation.ExceptionHandler(org.springframework.web.HttpMediaTypeNotAcceptableException.class)
    @ResponseBody
    public Response handleHttpMediaTypeNotAcceptableException(HttpServletRequest request, Exception ex) {
        logger.error("HttpMediaTypeNotAcceptableException uri:{}, code:{}, msg:{}", request.getRequestURI(), 405, ex.getMessage());
        logger.error("HttpMediaTypeNotAcceptableException", ex);
        Response exceptionResponse = new Response();
        exceptionResponse.setStatus(405);
        exceptionResponse.setMsg(ex.getMessage());
        return exceptionResponse;
    }

    @org.springframework.web.bind.annotation.ExceptionHandler(org.springframework.web.HttpRequestMethodNotSupportedException.class)
    @ResponseBody
    public Response handleHttpRequestMethodNotSupportedException(HttpServletRequest request, Exception ex) {
        logger.error("HttpRequestMethodNotSupportedException uri:{}, code:{}, msg:{}", request.getRequestURI(), 405, ex.getMessage());
        Response exceptionResponse = new Response();
        exceptionResponse.setStatus(405);
        exceptionResponse.setMsg(ex.getMessage());
        return exceptionResponse;
    }

    @org.springframework.web.bind.annotation.ExceptionHandler(org.springframework.web.bind.MissingServletRequestParameterException.class)
    @ResponseBody
    public Response handleMissingServletRequestParameterException(HttpServletRequest request, Exception ex) {
        logger.error("MissingServletRequestParameterException uri:{}, code:{}, msg:{}", request.getRequestURI(), 400, ex.getMessage());
        Response exceptionResponse = new Response();
        exceptionResponse.setStatus(400);
        exceptionResponse.setMsg(ex.getMessage());
        return exceptionResponse;
    }

    @org.springframework.web.bind.annotation.ExceptionHandler(BusinessException.class)
    @ResponseBody
    public Response handleBusinessException(HttpServletRequest request, Exception ex) {

        Response exceptionResponse;
        String uri = request.getRequestURI();
        BaseException e = (BaseException) ex;
        int code = e.getErrcode();
        String msg = e.getMsg();
        logger.error("caught error api:{}, errcode:{}, msg:{}", Log.api(uri), Log.errcode(code), Log.msg(msg), Log.error());
        if (e.getException() != null) {
            logger.error("caught error api:{}, error info", Log.exception(e.getException()));
        }
        exceptionResponse = new Response(code, msg);
        return exceptionResponse;
    }

    @org.springframework.web.bind.annotation.ExceptionHandler(SecurityException.class)
    @ResponseBody
    public Response handleSecurityException(HttpServletRequest request, Exception ex) {
        Response exceptionResponse;
        BaseException e = (BaseException) ex;
        int code = e.getErrcode();
        String msg = e.getMsg();
        exceptionResponse = new Response(code, msg);
        return exceptionResponse;
    }

    /**
     * beanValidator 参数校验异常
     *
     * @param request
     * @param ex
     * @return
     */
    @org.springframework.web.bind.annotation.ExceptionHandler(ValidationException.class)
    @ResponseBody
    public Response handleValidationException(HttpServletRequest request, Exception ex) {
        Response exceptionResponse = new Response();
        javax.validation.ValidationException validationException = (javax.validation.ValidationException) ex;
        validationException.getMessage();
        logger.error(" beanValidator 参数校验未通过 api:{}, errcode:{}, msg:{}", Log.api(request.getRequestURI()), Log.errcode(500), Log.msg(validationException.getMessage()));
        exceptionResponse.setStatus(500);
        exceptionResponse.setMsg(validationException.getMessage());
        return exceptionResponse;
    }

    /**
     * 参数绑定异常
     *
     * @param request
     * @param ex
     * @return
     */
    @org.springframework.web.bind.annotation.ExceptionHandler(BindException.class)
    @ResponseBody
    public Response handleBindException(HttpServletRequest request, Exception ex) {
        Response exceptionResponse = new Response();
        org.springframework.validation.BindException c = (org.springframework.validation.BindException) ex;
        List<ObjectError> errors = c.getBindingResult().getAllErrors();
        StringBuffer errorMsg = new StringBuffer();
        errors.stream().forEach(x -> errorMsg.append(x.getDefaultMessage()).append(";"));
        logger.error(" beanValidator 校验未通过 api:{}, errcode:{}, msg:{}", Log.api(request.getRequestURI()), Log.errcode(500), Log.msg(errorMsg.toString()));
        exceptionResponse.setStatus(500);
        exceptionResponse.setMsg(errorMsg.toString());
        return exceptionResponse;
    }

    /**
     * 未知运行时异常
     *
     * @param request
     * @param ex
     * @return
     */
    @org.springframework.web.bind.annotation.ExceptionHandler(Exception.class)
    @ResponseBody
    public Response handleException(HttpServletRequest request, Exception ex) {
        logger.error("uncaught error api:{}, errcode:{}, msg:{}", Log.api(request.getRequestURI()), Log.errcode(500), Log.msg("内部错误"), Log.error());
        logger.error("uncaught error ", Log.exception(ex), Log.api(request.getRequestURI()));
        logger.error("uncaught error ", ex);
        Response exceptionResponse = new Response();
        exceptionResponse.setStatus(500);
        exceptionResponse.setMsg("内部错误");
        return exceptionResponse;
    }
}

